package com.my.launcher;

import com.my.launcher.config.LauncherService;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.*;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 自定义启动器
 * @author timo 2021/2/6
 */
public class LauncherApplication {
    /**
     *
     * @param appName
     * @param resourceName 指定获取配置属性的文件 比如激活信息 nacos地址
     * @param source
     * @param args
     * @return
     */
    public static ConfigurableApplicationContext run(String appName,
                                                     String resourceName,
                                                     Class source,
                                                     String... args) throws IOException {
        SpringApplicationBuilder builder = createSpringApplicationBuilder(appName,resourceName, source, args);
        return builder.run(args);
    }

    public static SpringApplicationBuilder createSpringApplicationBuilder(final String appName,
                                                                          final String resourceName,
                                                                          final Class source, final String... args) throws IOException {
        //服务名不能为空
        Assert.hasText(appName, "[appName]\u670d\u52a1\u540d\u4e0d\u80fd\u4e3a\u7a7a");
        //https://baijiahao.baidu.com/s?id=1693202158387889642&wfr=spider&for=pc
        //https://blog.csdn.net/xby7437/article/details/114654912
        ConfigurableEnvironment environment = new StandardEnvironment();
        /*
            PropertySources（Iterable）是一个包含一个或多个属性源PropertySource对象的Holder，提供了判断是否存在给定name对应的属性源和获取给定name对应的属性源的操作。
            MutablePropertySources为属性源Holder PropertySource的具体实现，内部通过一个属性源集合（CopyOnWriteArrayList）来管理内部的属性源， 主要提供添加、移除、替换、是否包含属性源操作，这些操作实际上通过 CopyOnWriteArrayList 的相应操作完成
        */
        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.addFirst(new SimpleCommandLinePropertySource(args));
        propertySources.addLast(new MapPropertySource("systemProperties", environment.getSystemProperties()));
        propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", environment.getSystemEnvironment()));
        //此处无法获取
        String[] activeProfiles = environment.getActiveProfiles();
//        List<String> profiles = Arrays.asList(activeProfiles);
////        final List<String> presetProfiles = new ArrayList<String>(Arrays.asList("dev", "test", "prod"));
////        presetProfiles.retainAll(profiles);
//        List<String> activeProfileList = new ArrayList<String>(profiles);
//        Function<Object[], String> joinFun = StringUtils::arrayToCommaDelimitedString;
//        SpringApplicationBuilder builder = new SpringApplicationBuilder(new Class[]{source});
//        String profile;
//        if (activeProfileList.isEmpty()) {
//            profile = "dev";
//            activeProfileList.add(profile);
//            builder.profiles(new String[]{profile});
//        } else {
//            if (activeProfileList.size() != 1) {
//                //同时存在环境变量
//                throw new RuntimeException("\u540c\u65f6\u5b58\u5728\u73af\u5883\u53d8\u91cf:[" + StringUtils.arrayToCommaDelimitedString((Object[]) activeProfiles) + "]");
//            }
//            profile = activeProfileList.get(0);
//        }
//        String startJarPath = LauncherApplication.class.getResource("/").getPath().split("!")[0];
//        String activePros = joinFun.apply(activeProfileList.toArray());
//        //启动中，读取到的环境变量:[%s]，jar地址
//        System.out.println(String.format("----\u542f\u52a8\u4e2d\uff0c\u8bfb\u53d6\u5230\u7684\u73af\u5883\u53d8\u91cf:[%s]\uff0cjar\u5730\u5740:[%s]----",
//                activePros, startJarPath));
        SpringApplicationBuilder builder = new SpringApplicationBuilder(new Class[]{source});

        Properties props = System.getProperties();
        props.setProperty("spring.application.name", appName);

        Properties propsRead = readVersionAndNameFromProperties(resourceName);
        String active  = propsRead.getProperty("spring.profiles.active");
//        String nacosAddr  = propsRead.getProperty("nacosAddr");

        props.setProperty("spring.profiles.active", active);
        props.setProperty("spring.main.allow-bean-definition-overriding", "true");
        props.setProperty("spring.sleuth.sampler.percentage", "1.0");
//        props.setProperty("spring.cloud.nacos.config.shared-dataids", NacosConstant.sharedDataIds(profile));
//        props.setProperty("spring.cloud.nacos.config.refreshable-dataids", NacosConstant.sharedDataIds(profile));
//        props.setProperty("spring.cloud.nacos.config.file-extension", "yaml");
//        props.setProperty("spring.cloud.alibaba.seata.tx-service-group", appName.concat("-group"));
        List<LauncherService> launcherList = new ArrayList<LauncherService>();
        //查找所有LauncherService的实现类
        ServiceLoader.load(LauncherService.class).forEach(launcherList::add);
//        launcherList.stream()
//                .sorted(Comparator.comparing((Function<? super Object, ? extends Comparable>)LauncherService::getOrder))
//                .collect((Collector<? super Object, ?, List<? super Object>>) Collectors.toList())
//                .forEach(launcherService -> launcherService.launcher(builder, appName, profile, isLocalDev()));
//        return builder;
//        ((List) launcherList.stream().sorted(Comparator.comparing(LauncherService::getOrder)).collect(Collectors.toList()))
//                .forEach((launcherService) -> {
//            launcherService.launcher(builder, appName, profile, isLocalDev());
//        });
        List<LauncherService> collect = launcherList.stream().sorted(Comparator.comparing(LauncherService::getOrder)).collect(Collectors.toList());
        collect.forEach((launcherService) -> {
            launcherService.launcher(builder, appName,propsRead,isLocalDev());
        });
        return builder;
    }
    //不使用Environment的情况下（spring项目还未启动）直接获取配置文件属性
    private static Properties readVersionAndNameFromProperties(String resourceName) throws IOException {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Properties props = new Properties();
        InputStream resourceStream = loader.getResourceAsStream(resourceName);
        props.load(resourceStream);
        assert resourceStream != null;
        resourceStream.close();
        return props;
    }
    public static boolean isLocalDev() {
        final String osName = System.getProperty("os.name");
        return StringUtils.hasText(osName) && !"LINUX".equals(osName.toUpperCase());
    }
}



